.include "tn13adef.inc"
.include "usbmacro.inc"

.equ F_CPU = 12000000

.def GRB = R0
.def TMP = R16
.def TMP2 = R17
.def ARG0 = R20
.def ARG1 = R21
.def RVAL = R19
.def ZERO = R31
.def J = R28
.def K = R29
.def SE0 = R31
.def UIN = R31
.def UOUT = R26

.equ MASK_DP1 = (1 << PB0)
.equ MASK_DM1 = (1 << PB2)

.equ PORT1 = MASK_DP1 | MASK_DM1
.equ FS_J = MASK_DP1
.equ FS_K = MASK_DM1
.equ SE_0 = 0

; Two cycles delay
.macro nop2
  cbi PORTB, PB5
.endm

; Three cycles delay
.macro nop3
  lpm
.endm

; Eight cycles delay
.macro nop8
  rcall pnop8
.endm

.macro outi
  ldi TMP, @1
  out @0, TMP
.endm

; wait for the next "ms" timer ticks, which occur at 1ms intervals
.macro wait_ms
  ldi ARG0, @0
  rcall pwait_ms
.endm

; Wait for next frame and send SOF.
; Returns 0 if the device is not present.
.macro send_sof
  ldi ARG1, @0
  rcall psend_sof
.endm

.cseg

.org 0 ; Entry point

  ; Stack setup
	outi SPL, low(RAMEND)

  ; Constants setup
  ldi ZL, 0
  ldi ZH, 0
  ldi UOUT, PORT1
  ldi J, FS_J
  ldi K, FS_K

  ; Timer setup
  ;out TIMSK0, ZERO
  outi OCR0A, 46 ; ~1 ms
  outi TCCR0A, (1 << WGM01)
  outi TCCR0B, (1 << CS02)

  ; Init USB
  usbd UIN
  usbs SE0
  wait_ms 100

mainloop:
  ; if the device doesn't appear present, do nothing
  in TMP, PINB
  and TMP, UOUT
  ldi TMP2, FS_J
  and TMP2, UOUT
  cpse TMP, TMP2
  rjmp mainloop
  ; perform reset
	wait_ms 100
	rcall send_reset
	; perform basic enumeration
	send_sof 10
	rcall send_set_addr
	send_sof 3
	rcall send_set_conf
	; now send empty frames as long as the device is present.
waitloop:
  send_sof 1
  tst RVAL
  brne waitloop
  rjmp mainloop

; See wait_ms
pwait_ms:
  outi TIFR0, (1 << OCF0A)
wait_ms_loop:
  in TMP, TIFR0
  andi TMP, (1 << OCF0A)
  breq wait_ms_loop
  dec ARG0
  brne pwait_ms
  ret

; Send bus reset
send_reset:
  usbs SE0
  usbd UOUT
  wait_ms 10 
  usbd UIN
  ret

; See send_sof
psend_sof:
  wait_ms 1
  ldi RVAL, 0
  in TMP, PINB
  and TMP, UOUT
  ldi TMP2, FS_J
  and TMP2, UOUT
  cpse TMP, TMP2
  ret
  usbd UOUT
  ; send SOF 1337
  usbs7 K, J, K, J, K, J, K
  nop2
  usbs6 J, J, K, J, J, K
  nop2
  usbs2 J, K
  nop3
  usbs4 J, K, K, J
  nop2
  nop3
  usbs4 K, SE0, SE0, J
  usbd UIN
  usbs SE0
  dec ARG1
  brne psend_sof
pnop8:
  ldi RVAL, 1
  ret

; Send SET_ADDRESS
send_set_addr:
  usbd UOUT
	; send SETUP
  usbs7 K, J, K, J, K, J, K
  nop2
  usbs J
  nop2
  usbs10 K, K, J, K, J, K, J, K, J, K
  usbs10 J, K, J, K, J, K, K, J, K, J
  usbs3  SE0, SE0, J
	; delay a little
	nop8
	; send DATA0
  usbs7 K, J, K, J, K, J, K
  nop3
  usbs4 J, K, J, K
  nop2
  usbs10 J, K, J, K, J, K, J, K, K, J
  usbs10 J, K, J, K, J, K, K, J, K, J
  usbs10 K, J, K, J, K, J, K, J, K, J
  usbs10 K, J, K, J, K, J, K, J, K, J
  usbs10 K, J, K, J, K, J, K, J, K, J
  usbs10 K, J, K, J, K, J, K, J, K, J
  usbs4  K, J, K, J
  nop2
  usbs3 K, K, J
  nop2
  nop2
  usbs10 K, K, J, K, K, J, K, SE0, SE0, J
	usbd UIN
	usbs SE0
  ; device will send ACK now (within 16 bit times)
	; wait until new frame; an immediate IN will just get NAKed
  send_sof 1
  usbd UOUT
	; send IN
	usbs7 K, J, K, J, K, J, K
  nop2
  usbs4 J, K, K, J
  nop2
  usbs10 K, J, K, J, K, J, K, J, K, J 
  usbs10 K, J, K, K, J, K, J, SE0, SE0, J
	; device will send DATA1 now.
	usbd UIN
	usbs SE0
  ; receive DATA1
  rjmp recv_data1

; Send SET_CONFIGURATION
send_set_conf:
	usbd UOUT
	; send SETUP
	usbs7 K, J, K, J, K, J, K
  nop2
  usbs J
  nop2
  usbs10 K, K, J, K, K, J, K, J, K, J
  usbs7  K, J, K, J, K, K, J
  nop3
  usbs3 SE0, SE0, J
	; delay a little
	nop8
	; send DATA0
	usbs7 K, J, K, J, K, J, K
  nop3
  usbs4 J, K, J, K
  nop2
  usbs10 J, K, J, K, J, K, J, K, K, J
  usbs10 K, K, J, K, J, K, K, J, K, J
  usbs10 K, J, K, J, K, J, K, J, K, J
  usbs10 K, J, K, J, K, J, K, J, K, J
  usbs10 K, J, K, J, K, J, K, J, K, J
  usbs10 K, J, K, J, K, J, K, J, K, J
  usbs4  K, J, K, J
  nop3
  usbs10 K, J, J, K, J, J, K, K, J, K
  usbs6  K, J, K, SE0, SE0, J
  usbd UIN
	usbs SE0
	; device will send ACK now (within 16 bit times)
	; wait until new frame; an immediate IN will just get NAKed
	send_sof 1
	usbd UOUT
	; send IN
	usbs7 K, J, K, J, K, J, K
  nop2
  usbs4 J, K, K, J
  nop2
  usbs10 K, K, J, K, J, K, J, K, J, K
  usbs4  J, K, K, J
  nop3
  usbs3 SE0, SE0, J
	; device will send DATA1 now.
	usbd UIN
	usbs SE0
  ; receive DATA1
  rjmp recv_data1

recv_data1:
  ; delay 44 cycles
  ldi TMP, 14
recv_data1_loop:
  dec TMP
  brne recv_data1_loop
  nop2
	usbd UOUT
	; send ACK
	usbs10 K, J, K, J, K, J, K, K, J, J
  usbs4  K, J, J, K
  nop2
  usbs3 SE0, SE0, J
	usbd UIN
	usbs SE0
  ret
